#include "BitmapFont.h"
#include "../TinyXML/tinyxml.h"
#include "../SGD Wrappers/CSGD_TextureManager.h"

BitmapFont* BitmapFont::pInstance = nullptr;
// Constructor
BitmapFont::BitmapFont(void)
{
}

// Destructor
BitmapFont::~BitmapFont(void)
{
}

BitmapFont* BitmapFont::GetInstance( void )
{
	// Allocate the static pointer if necessary
	if( pInstance == nullptr )
		pInstance = new BitmapFont;

	// Return the singleton
	return pInstance;
}
void BitmapFont::DeleteInstance( void )
{
	BitmapFont::GetInstance()->UnloadAll();
	delete pInstance;
	pInstance = nullptr;
}

// GetTextLength
//	- Calculates and returns the width in pixels of a string of text.
//	text : The text to get the width of.
//	fontIndex : The id of the font that used for the calculation.
int BitmapFont::GetTextLength(const char* text, unsigned int fontIndex)
{
	int width = 0;

	if(fontIndex < GetInstance()->fonts.size())
	{
		Font font = GetInstance()->fonts[fontIndex];

		for(int i = 0; text[i] != '\0'; ++i)
			width += font.GetRect(text[i]).right - font.GetRect(text[i]).left;
	}

	return width;
}

// GetTextLength
//	- Calculates and returns the width in pixels of a string of text.
//	text : The text to get the width of.
//	fontIndex : The id of the font that used for the calculation.
int BitmapFont::GetTextLength(std::string text, unsigned int fontIndex)
{
	return GetTextLength(text.c_str(), fontIndex);
}

// GetTextHeight
//	- Returns the height of the tallest character in the string of text.
//	text : The text to get the height of.
//	fontIndex : The id of the font that used for the calculation.
int BitmapFont::GetTextHeight(const char* text, unsigned int fontIndex)
{
	int height = 0;

	if(fontIndex < GetInstance()->fonts.size())
	{
		Font font = GetInstance()->fonts[fontIndex];

		for(int i = 0; text[i] != '\0'; ++i)
			height = max(height, font.GetRect(text[i]).bottom - font.GetRect(text[i]).top);
	}

	return height;
}

// GetTextHeight
//	- Returns the height of the tallest character in the string of text.
//	text : The text to get the height of.
//	fontIndex : The id of the font that used for the calculation.
int BitmapFont::GetTextHeight(std::string text, unsigned int fontIndex)
{
	return GetTextHeight(text.c_str(), fontIndex);
}

// LoadFont
//	- Loads a font from the specified filename/filepath.
//	- RETURNS the index to the font int the vector.
int BitmapFont::LoadFont(std::string filename)
{
	TiXmlDocument doc;
	doc.LoadFile(filename.c_str());

	TiXmlElement* rootEl = doc.FirstChildElement("font");
	Font tempFont;

	TiXmlElement* infoEl = rootEl->FirstChildElement("info");
	tempFont.SetName(infoEl->Attribute("face"));
	int size; infoEl->Attribute("size",&size);

	TiXmlElement* pagesEl = rootEl->FirstChildElement("pages");
	TiXmlElement* pageEl = pagesEl->FirstChildElement("page");
	const char* filePath = pageEl->Attribute("file");
	if(filePath != nullptr)
	{
		tempFont.SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(filePath));
	}
	if(tempFont.GetImageID() != -1)
	{
		TiXmlElement* charsEl = rootEl->FirstChildElement("chars");
		for(TiXmlElement* charEl = charsEl->FirstChildElement("char"); charEl != nullptr; charEl = charEl->NextSiblingElement("char"))
		{
			int tempLetter;  charEl->Attribute("id", &tempLetter);
			char letterToAdd = (char)tempLetter;
			RECT rectToAdd;
			double tempPoint;

			charEl->Attribute("x", &tempPoint);
			rectToAdd.left = (LONG)tempPoint;
			charEl->Attribute("y", &tempPoint);
			rectToAdd.top = (LONG)tempPoint;
			charEl->Attribute("width", &tempPoint);
			rectToAdd.right = (LONG)(rectToAdd.left + tempPoint);
			charEl->Attribute("height", &tempPoint);
			rectToAdd.bottom = (LONG)(rectToAdd.top + tempPoint);


			tempFont.AddRect(letterToAdd,rectToAdd);
		}
	}
	else
	{
		assert("Unable to load image for bitmap font!");
	}

	fonts.push_back(tempFont);

	return fonts.size() - 1;
}

// Print
//	- Prints the specified font at the specified position.
void BitmapFont::Print(std::string text, float PosX, float PosY, int index, DWORD dwColor, float scale)
{
	//Offset the fact that we're drawing from the bottom
	PosY+= 20;
	int startPosX = (int)PosX;
	for(unsigned int curChar = 0; curChar < text.size(); ++curChar)
	{
		if(text[curChar] == '\\')
		{
			if(text[curChar+1] == 'n')
			{
				//Move down a line
				PosY += 21.0f;
				PosX = (float)startPosX;
			}
			curChar += 1;
			continue;
		}
		//Draw from the bottom to line up upper/lowercase
		float tempPosY = PosY - (fonts[index].GetRect(text[curChar]).bottom - fonts[index].GetRect(text[curChar]).top);
		//Draw each individual letter
		CSGD_TextureManager::GetInstance()->Draw(fonts[index].GetImageID(),(int)PosX,(int)tempPosY,
												scale,scale,
												&fonts[index].GetRect(text[curChar])
												,0.0f,0.0f,0.0f,
												dwColor);
		//Move over based upon the character's width you just printed
		PosX += (fonts[index].GetRect(text[curChar]).right -fonts[index].GetRect(text[curChar]).left);
	}
}


// Print (with width)
//	- Prints the specified font at the specified position, and moves down a line if it exceeds the width in Pixels
void BitmapFont::Print(std::string text, float PosX, float PosY, int index,int width, DWORD dwColor, float scale)
{
	//Offset the fact that we're drawing from the bottom
	PosY+= 20;
	int startPosX = (int)PosX;
	for(unsigned int curChar = 0; curChar < text.size(); ++curChar)
	{
		if(PosX - startPosX > width)
		{
			//Move down a line
			PosY += 21.0f;
			PosX = (float)startPosX;
		}
		if(text[curChar] == '\\')
		{
			if(text[curChar+1] == 'n')
			{
				//Move down a line
				PosY += 21.0f;
				PosX = (float)startPosX;
			}
			curChar += 1;
			continue;
		}
		//Draw from the bottom to line up upper/lowercase
		float tempPosY = PosY - (fonts[index].GetRect(text[curChar]).bottom - fonts[index].GetRect(text[curChar]).top);
		//Draw each individual letter
		CSGD_TextureManager::GetInstance()->Draw(fonts[index].GetImageID(),(int)PosX,(int)tempPosY,
												scale,scale,
												&fonts[index].GetRect(text[curChar])
												,0.0f,0.0f,0.0f,
												dwColor);
		//Move over based upon the character's width you just printed
		PosX += (fonts[index].GetRect(text[curChar]).right -fonts[index].GetRect(text[curChar]).left);
	}
}

// UnloadAll
//	- Unloads all fonts from memory.
void BitmapFont::UnloadAll(void)
{
	for(unsigned int curFont = 0; curFont < fonts.size(); ++curFont)
	{
		if(fonts[curFont].GetImageID() != -1)
		{
			CSGD_TextureManager::GetInstance()->UnloadTexture(fonts[curFont].GetImageID());
		}

	}
	fonts.clear();
}
